-
Notifications
You must be signed in to change notification settings - Fork 48
feat: optimize RichView styles to match Android app #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add V2EX preset stylesheet with styles matching the Android app: - Smaller heading sizes (h1: 22, h2: 18, h3: 16, h4: 15, h5: 12, h6: 10) - Medium font weight for headings (matching Android's 500) - Body text color #555555 (gray) for light mode - Link color #778087 (grayish) matching V2EX web style - Blockquote: 3px left border with subtle background - Code: 80% font size (13px) relative to body Add new styling components: - TableStyle: header font weight, separator color, cell padding - HorizontalRuleStyle: color, height, vertical padding Add rendering support for HTML tags: - <u> underline with underlineStyle attribute - <sup> superscript with smaller font and positive baseline offset - <sub> subscript with smaller font and negative baseline offset Update MarkdownRenderer to use stylesheet styles for: - Horizontal rules - Table headers and separators 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR enhances the RichView rendering system to match the Android app's styling by adding a V2EX preset stylesheet, introducing new style components for tables and horizontal rules, and adding support for underline, superscript, and subscript HTML tags.
Key Changes
- Added
TableStyleandHorizontalRuleStylecomponents with configurable properties for consistent table and horizontal rule rendering - Implemented V2EX preset stylesheet with colors, font sizes, and spacing matching the Android app's CSS (e.g., body text at 16px with
#555555color, heading sizes ranging from 10-22px) - Added HTML tag rendering support for
<u>(underline),<sup>(superscript with 70% font size and baseline offset), and<sub>(subscript with 70% font size and negative baseline offset)
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| V2er/Sources/RichView/Renderers/MarkdownRenderer.swift | Adds horizontal rule rendering function using new stylesheet property; implements HTML tag parsing for underline, superscript, and subscript; updates table rendering to use new TableStyle properties |
| V2er/Sources/RichView/Models/RenderStylesheet.swift | Defines TableStyle and HorizontalRuleStyle structs; adds V2EX preset stylesheet with Android-matching styles; extends default stylesheet with table and horizontal rule styles |
| CLAUDE.md | Documents Android project location reference |
| // Check for underline (<u>text</u>) | ||
| if let underlineMatch = currentText.firstMatch(of: /<u>(.+?)<\/u>/) { | ||
| // Add text before underline | ||
| let beforeRange = currentText.startIndex..<underlineMatch.range.lowerBound | ||
| if !beforeRange.isEmpty { | ||
| result.append(renderPlainText(String(currentText[beforeRange]))) | ||
| } | ||
|
|
||
| // Add underlined text | ||
| var underlineText = AttributedString(String(underlineMatch.1)) | ||
| underlineText.font = .system(size: stylesheet.body.fontSize) | ||
| underlineText.foregroundColor = stylesheet.body.color.uiColor | ||
| underlineText.underlineStyle = .single | ||
| result.append(underlineText) | ||
|
|
||
| // Continue with remaining text | ||
| currentText = String(currentText[underlineMatch.range.upperBound...]) | ||
| continue | ||
| } | ||
|
|
||
| // Check for superscript (<sup>text</sup>) | ||
| if let supMatch = currentText.firstMatch(of: /<sup>(.+?)<\/sup>/) { | ||
| // Add text before superscript | ||
| let beforeRange = currentText.startIndex..<supMatch.range.lowerBound | ||
| if !beforeRange.isEmpty { | ||
| result.append(renderPlainText(String(currentText[beforeRange]))) | ||
| } | ||
|
|
||
| // Add superscript text (smaller font, baseline offset) | ||
| var supText = AttributedString(String(supMatch.1)) | ||
| supText.font = .system(size: stylesheet.body.fontSize * 0.7) | ||
| supText.foregroundColor = stylesheet.body.color.uiColor | ||
| supText.baselineOffset = stylesheet.body.fontSize * 0.3 | ||
| result.append(supText) | ||
|
|
||
| // Continue with remaining text | ||
| currentText = String(currentText[supMatch.range.upperBound...]) | ||
| continue | ||
| } | ||
|
|
||
| // Check for subscript (<sub>text</sub>) | ||
| if let subMatch = currentText.firstMatch(of: /<sub>(.+?)<\/sub>/) { | ||
| // Add text before subscript | ||
| let beforeRange = currentText.startIndex..<subMatch.range.lowerBound | ||
| if !beforeRange.isEmpty { | ||
| result.append(renderPlainText(String(currentText[beforeRange]))) | ||
| } | ||
|
|
||
| // Add subscript text (smaller font, negative baseline offset) | ||
| var subText = AttributedString(String(subMatch.1)) | ||
| subText.font = .system(size: stylesheet.body.fontSize * 0.7) | ||
| subText.foregroundColor = stylesheet.body.color.uiColor | ||
| subText.baselineOffset = -stylesheet.body.fontSize * 0.2 | ||
| result.append(subText) | ||
|
|
||
| // Continue with remaining text | ||
| currentText = String(currentText[subMatch.range.upperBound...]) | ||
| continue | ||
| } |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new underline, superscript, and subscript HTML tag rendering features lack test coverage. Since V2erTests/RichView/MarkdownRendererTests.swift has comprehensive tests for other inline formatting features (bold, italic, code, links, mentions, strikethrough, highlights), these new features should also have corresponding test cases to ensure they work correctly.
| public struct TableStyle: Equatable { | ||
| public var headerFontWeight: Font.Weight | ||
| public var headerBackgroundColor: Color | ||
| public var cellPadding: CGFloat | ||
| public var separatorColor: Color | ||
| public var separatorWidth: CGFloat | ||
| public var alternateRowColor: Color? | ||
|
|
||
| public init( | ||
| headerFontWeight: Font.Weight = .semibold, | ||
| headerBackgroundColor: Color = .clear, | ||
| cellPadding: CGFloat = 8, | ||
| separatorColor: Color = Color.gray.opacity(0.3), | ||
| separatorWidth: CGFloat = 0.5, | ||
| alternateRowColor: Color? = nil | ||
| ) { | ||
| self.headerFontWeight = headerFontWeight | ||
| self.headerBackgroundColor = headerBackgroundColor | ||
| self.cellPadding = cellPadding | ||
| self.separatorColor = separatorColor | ||
| self.separatorWidth = separatorWidth | ||
| self.alternateRowColor = alternateRowColor | ||
| } |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Several properties in TableStyle (headerBackgroundColor, cellPadding, separatorWidth, alternateRowColor) are defined but not currently used in the table rendering logic. Consider either implementing these properties in the rendering code or adding documentation comments explaining that they are reserved for future use.
| public struct HorizontalRuleStyle: Equatable { | ||
| public var color: Color | ||
| public var height: CGFloat | ||
| public var verticalPadding: CGFloat | ||
|
|
||
| public init( | ||
| color: Color = Color(hex: "#f4f2f2"), | ||
| height: CGFloat = 0.8, | ||
| verticalPadding: CGFloat = 8 | ||
| ) { | ||
| self.color = color | ||
| self.height = height | ||
| self.verticalPadding = verticalPadding | ||
| } | ||
| } |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The height and verticalPadding properties in HorizontalRuleStyle are defined but not currently used in the horizontal rule rendering logic (which uses a fixed character-based rendering approach). Consider either implementing these properties in the rendering code or adding documentation comments explaining that they are reserved for future use when the rendering approach changes.
CLAUDE.md
Outdated
| - **CHANGELOG.md is required** for all releases - the build will fail if the current version is missing from the changelog | ||
| - Always install to Gray'iPhone if it connected, otherwise install to simulator | ||
| - Always install to Gray'iPhone if it connected, otherwise install to simulator | ||
| - the coresponding android project located in ../v2er-android |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: "coresponding" should be spelled "corresponding".
| - the coresponding android project located in ../v2er-android | |
| - the corresponding android project located in ../v2er-android |
| } else if line.starts(with: "---") { | ||
| // Horizontal rule | ||
| attributedString.append(AttributedString("—————————————\n")) | ||
| attributedString.append(renderHorizontalRule()) |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The horizontal rule character has been changed from "—" (em dash) to "─" (box drawing character), but the existing test in MarkdownRendererTests.swift line 290 still checks for "—". This will cause the test to fail. Consider updating the test to check for "─" instead.
Code Coverage Report ❌Current coverage: 26.44% |
- Fix typo in CLAUDE.md ("coresponding" → "corresponding")
- Update horizontal rule test to use box drawing character (─)
- Add tests for underline, superscript, and subscript rendering
- Add documentation for reserved style properties in TableStyle
and HorizontalRuleStyle
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
Code Coverage Report ❌Current coverage: 27.98% |
Summary
Changes
V2EX Preset Stylesheet
Matches the Android app's
v2er.cssandfont.css:#555555(gray) for light mode#778087(grayish V2EX style)rgba(126, 126, 126, 0.5)color.darkCSS classesNew Style Components
TableStyle: header font weight, separator color/width, cell padding, alternate row colorHorizontalRuleStyle: color, height, vertical paddingHTML Tag Rendering
<u>underline rendering withunderlineStyle = .single<sup>superscript with 70% font size and positive baseline offset<sub>subscript with 70% font size and negative baseline offsetTest plan
🤖 Generated with Claude Code